home *** CD-ROM | disk | FTP | other *** search
Text File | 1993-09-16 | 41.1 KB | 1,035 lines | [TEXT/CCL2] |
- ;;-*- Mode: Lisp; Package: CCL -*-
- ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
- ;; scroll-bar-dialog-items.lisp
- ;;
- ;;
- ;; ©1989, Apple Computer, Inc
- ;;
- ;; the code in this file implements a scroll-bar class of dialog-items
- ;;
-
-
- ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
- ;;
- ;; Change history
- ;;
- ;; 04/28/93 mwp Release
- ;; 07/17/92 bill Do the right thing for :view-size initarg and
- ;; no :length or :width initarg.
- ;; 06/04/92 bill Do not ignore the :setting initarg
- ;; ------------
- ;; 03/20/92 bill fix completely bogus conversions in mac-scroll-bar-setting
- ;; and outside-scroll-bar-setting.
- ;; ------------- 2.0f3
- ;; 01/06/92 bill Fix a bug in the ROM that enables a scroll bar on exiting
- ;; #_TrackControl. This allows user dialog-item-action functions
- ;; to disable the scroll bar while it is being tracked.
- ;; Adjust initial mouse position for scroll-position in
- ;; track-scroll-bar-thumb.
- ;; install-view-in-window disables the scroll bar if appropriate.
- ;; New mapping of user-visible min & max to what the ROM sees so
- ;; that the scroll bar will be disabled when max=min.
- ;; 12/30/91 bill :pane-splitter should be :left or :right for a
- ;; horizontal scroll bar (vice :top or :bottom)
- ;; set-scroll-bar-width works correctly for inactive scroll bars.
- ;; inactive scroll bars get drawn after set-view-container.
- ;; :srcxor -> :patxor
- ;; Window.updateRgn -> WindowRecord.updateRgn
- ;; Remove %pane-splitter-outline-position.
- ;; Thanx to STEVE.M
- ;; ------------- 2.0b4
- ;; 11/12/91 bill (from dds)
- ;; :control.vis -> :controlRecord.ContrlVis
- ;; :control.owner -> :controlRecord.ContrlOwner
- ;; 10/17/91 bill Use #_TrackControl vice track-scroll-bar-thumb if
- ;; not doing real time scrolling. Disable periodic tasks
- ;; that draw during real time scrolling.
- ;; 10/15/91 bill #_ShowControl & #_HideControl add to the invalid region.
- ;; Add a #_ValidRect in view-(de)activate-event-handler
- ;; -------------- 2.0b3
- ;; 08/26/91 bill no more (require 'traps)
- ;; 08/25/91 gb use new trap syntax.
- ;; 08/08/91 bill set-view-container now handles the view-deactivate-event-handler
- ;; that was in install-view-in-window here.
- ;; 07/18/91 bill Prevent divide by zero in mac-scroll-bar-setting
- ;; 04/16/91 bill pane-splitter-outline-position
- ;; 03/22/91 bill make scroll bars & pane-splitters disappear when the
- ;; window is not active.
- ;; 03/11/91 bill WRS's pane-splitter-corners fix.
- ;; 03/04/91 bill increase setting range to beyond [-32768 32767]
- ;; 02/22/91 bill make the scroll bar initially invisible so
- ;; we don't need to focus-view in install-view-in-window.
- ;;--------------- 2.0b1
- ;; 01/28/91 bill event.where -> eventRecord.where
- ;;
-
- (in-package :ccl)
-
- (eval-when (:compile-toplevel :load-toplevel :execute)
- (export '(scroll-bar-dialog-item scroll-bar-setting
- scroll-bar-min scroll-bar-max scroll-bar-length scroll-bar-width
- scroll-bar-page-size scroll-bar-scroll-size scroll-bar-scrollee
- set-scroll-bar-setting set-scroll-bar-min set-scroll-bar-max
- set-scroll-bar-length set-scroll-bar-width set-scroll-bar-scrollee
- scroll-bar-changed track-scroll-bar
- scroll-bar-track-thumb-p set-scroll-bar-track-thumb-p
- pane-splitter split-pane pane-splitter-corners
- pane-splitter-position set-pane-splitter-position
- draw-pane-splitter-outline pane-splitter-outline-position
- view-scroll-bars)
- :ccl))
-
-
- ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
- ;; a few things that need to be around at compile time, but not run time
- ;;
- (eval-when (:compile-toplevel :execute)
-
- ;some constants for tracking the clicks in the scroll-bar
- (defconstant $InUpButton 20)
- (defconstant $InDownButton 21)
- (defconstant $InPageUp 22)
- (defconstant $InPageDown 23)
- (defconstant $InThumb 129))
-
- ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
- ;;scroll-bar-dialog-item
- ;;
-
- (defclass scroll-bar-dialog-item (control-dialog-item)
- ((procid :allocation :class :initform #$scrollBarProc)
- (direction :initarg :direction :reader scroll-bar-direction)
- (min :initarg :min :reader scroll-bar-min)
- (max :initarg :max :reader scroll-bar-max)
- (setting :initarg :setting :reader scroll-bar-setting)
- (track-thumb-p :initarg :track-thumb-p :initform nil
- :accessor scroll-bar-track-thumb-p)
- (page-size :initarg :page-size :initform 5 :accessor scroll-bar-page-size)
- (scroll-size :initarg :scroll-size :initform 1 :accessor scroll-bar-scroll-size)
- (scrollee :initarg :scrollee :initform nil :reader scroll-bar-scrollee)
- (pane-splitter :initform nil :accessor pane-splitter)
- (pane-splitter-position :initform nil :initarg :pane-splitter
- :reader pane-splitter-position)))
-
- (defclass pane-splitter (simple-view)
- ((scrollee :initarg :scrollee
- :reader scroll-bar-scrollee)
- (direction :initarg :direction :reader scroll-bar-direction)
- (scroll-bar :initarg :scroll-bar :initform nil :reader scroll-bar)))
-
- ; Args would be in wrong order if these were defined as :writer's
- (defmethod set-scroll-bar-track-thumb-p ((item scroll-bar-dialog-item) value)
- (setf (scroll-bar-track-thumb-p item) value))
-
- (defmethod set-scroll-bar-scrollee ((view pane-splitter) value)
- (setf (slot-value view 'scrollee) value))
-
-
- ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
- ;;initialize-instance
- ;;
- ;;initargs:
- ;; length
- ;; width
- ;; direction
- ;; setting
- ;; min
- ;; max
- ;; page-size
- ;; track-thumb-p
- ;;
- ;;in addition, the standard dialog-item initargs can be used
- ;;Size can be specified by either the view-size initarg or
- ;;the length & width initargs, but not both.
- ;;
-
- (defmethod initialize-instance ((item scroll-bar-dialog-item) &rest initargs
- &key (min 0) (max 100) (setting 0) width
- (direction :vertical) length scrollee
- pane-splitter (pane-splitter-length 7) view-size
- view-position view-container)
- (declare (dynamic-extent initargs))
- (setq max (max min max)
- setting (min (max setting min) max))
- (if (and view-size (or length width))
- (error "Both ~s and ~s were specified."
- ':view-size (if length :length :width)))
- (unless length
- (setq length
- (if view-size
- (ecase direction
- (:vertical (point-v view-size))
- (:horizontal (point-h view-size)))
- 100)))
- (unless width
- (setq width
- (if view-size
- (ecase direction
- (:vertical (point-h view-size))
- (:horizontal (point-v view-size)))
- 16)))
- (when pane-splitter
- (let* ((splitter (make-instance 'pane-splitter
- :direction direction
- :width width
- :length pane-splitter-length
- :scroll-bar item
- :scrollee scrollee))
- (size (view-size splitter))
- (h (point-h size))
- (v (point-v size)))
- (setf (pane-splitter item) splitter)
- (if (eq direction :vertical)
- (progn
- (decf length v)
- (when view-position
- (let ((p-h (point-h view-position))
- (p-v (point-v view-position)))
- (if (eq pane-splitter :top)
- (progn
- (set-view-position splitter view-position)
- (setq view-position (make-point p-h (+ p-v v))))
- (progn
- (set-view-position splitter p-h (+ p-v length)))))))
- (progn
- (decf length h)
- (when view-position
- (let ((p-h (point-h view-position))
- (p-v (point-v view-position)))
- (if (eq pane-splitter :left)
- (progn
- (set-view-position splitter view-position)
- (setq view-position (make-point (+ p-h h) p-v)))
- (progn
- (set-view-position splitter (+ p-h length) p-v)))))))))
- (apply #'call-next-method
- item
- :min min
- :max max
- :setting setting
- :direction direction
- :length length
- :view-container nil
- :view-position view-position
- :view-size
- (case direction
- (:vertical (make-point width length))
- (:horizontal (make-point length width))
- (t (error "illegal :direction ~a (must be :vertical or :horizontal)."
- direction)))
- initargs)
- (when (and pane-splitter view-container (not view-position))
- (set-default-size-and-position item view-container)
- (set-view-position item (view-position item)))
- (when view-container
- (set-view-container item view-container))
- (when scrollee
- (add-view-scroll-bar scrollee item)))
-
- (defun view-scroll-bars (view)
- (view-get view 'scroll-bars))
-
- (defun add-view-scroll-bar (view scroll-bar)
- (pushnew scroll-bar (view-get view 'scroll-bars)))
-
- (defun delete-view-scroll-bar (view scroll-bar)
- (setf (view-get view 'scroll-bars)
- (delete scroll-bar (view-get view 'scroll-bars))))
-
- ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
- ;;install-view-in-window
- ;;
- ;; this is when we actually create the control (when the item
- ;; is added to a window)
-
- (defconstant $scroll-bar-max 16384)
-
- (defun mac-scroll-bar-min-max (min max &aux dif)
- (unless (>= max min) (setq max min))
- (cond ((and (>= min (- $scroll-bar-max)) (<= max $scroll-bar-max))
- (values min max))
- ((< (setq dif (- max min)) (+ $scroll-bar-max $scroll-bar-max))
- (let ((min-return
- (max (- $scroll-bar-max)
- (min min (- $scroll-bar-max dif)))))
- (values min-return (+ min-return dif))))
- (t (values (- $scroll-bar-max) $scroll-bar-max))))
-
- (defun mac-scroll-bar-setting (setting min max &optional mac-min mac-max)
- (if (<= max min)
- min
- (progn
- (unless (and mac-min mac-max)
- (multiple-value-setq (mac-min mac-max) (mac-scroll-bar-min-max min max)))
- (min mac-max
- (+ mac-min
- (round (* (- setting min) (- mac-max mac-min)) (- max min)))))))
-
- (defun outside-scroll-bar-setting (scroll-bar handle)
- (let ((mac-setting (#_GetCtlValue handle))
- (mac-min (#_GetCtlMin handle))
- (mac-max (#_GetCtlMax handle))
- (min (scroll-bar-min scroll-bar))
- (max (scroll-bar-max scroll-bar)))
- (declare (fixnum mac-min mac-max))
- (if (eql mac-min mac-max)
- mac-min
- (+ min (round (* (- mac-setting mac-min) (- max min)) (- mac-max mac-min))))))
-
- (defmethod install-view-in-window :after ((item scroll-bar-dialog-item) view)
- (declare (ignore view))
- (let* ((window (view-window item))
- (my-size (view-size item))
- (my-position (view-position item))
- (setting (scroll-bar-setting item))
- (min (scroll-bar-min item))
- (max (scroll-bar-max item))
- (mac-setting (mac-scroll-bar-setting setting min max)))
- (multiple-value-bind (mac-min mac-max) (mac-scroll-bar-min-max min max)
- (when window
- (rlet ((scroll-rect :rect))
- (rset scroll-rect rect.topleft my-position)
- (rset scroll-rect rect.bottomright (add-points my-position my-size))
- (let ((handle (dialog-item-handle item)))
- (setf (dialog-item-handle item) nil) ; I'm paranoid
- (when handle
- (#_DisposeControl handle)))
- (setf (dialog-item-handle item)
- (#_NewControl
- (wptr item) ;window
- scroll-rect ;item rectangle
- (%null-ptr) ;title
- nil ;visible-p: invisible initially.
- mac-setting ;initial value
- mac-min ;min value
- mac-max ;max value
- 16 ;type of control
- 0))) ;refcon
- (unless (dialog-item-enabled-p item)
- (#_HiliteControl (dialog-item-handle item) 255))
- ; Make sure the pane splitter is in the right place
- (when (pane-splitter item)
- (set-view-position item (view-position item)))))))
-
- ; This ensures that the scroll bar gets drawn right
- ; after it is installed.
- (defmethod set-view-container :after ((item scroll-bar-dialog-item) container)
- (when container
- (multiple-value-bind (tl br) (scroll-bar-and-splitter-corners item)
- (invalidate-corners container tl br))))
-
- (defmethod remove-view-from-window :before ((item scroll-bar-dialog-item))
- (let ((handle (dialog-item-handle item)))
- (when handle
- (setf (dialog-item-handle item) nil)
- (#_DisposeControl handle))))
-
-
- ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
- ;;view-draw-contents
- ;;
- ;;this function is called whenever the item needs to be drawn
- ;;
- ;;to draw the dialog-item, we just call _Draw1Control
- ;;unless we just created it and it's still invisible.
- ;;
-
- (defmethod view-draw-contents ((item scroll-bar-dialog-item))
- (let ((handle (dialog-item-handle item)))
- (when handle
- (if (window-active-p (view-window item))
- (if (neq 0 (href handle controlRecord.contrlvis))
- (#_Draw1Control handle)
- (#_ShowControl handle))
- (multiple-value-bind (tl br) (scroll-bar-and-splitter-corners item)
- (rlet ((rect :rect :topLeft tl :botRight br))
- (#_FrameRect rect)))))))
-
- (defun scroll-bar-and-splitter-corners (scroll-bar)
- (multiple-value-bind (tl br) (view-corners scroll-bar)
- (let ((splitter (pane-splitter scroll-bar)))
- (if splitter
- (multiple-value-bind (stl sbr) (view-corners splitter)
- (values (make-point (min (point-h tl) (point-h stl))
- (min (point-v tl) (point-v stl)))
- (make-point (max (point-h br) (point-h sbr))
- (max (point-v br) (point-v sbr)))))
- (values tl br)))))
-
- ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
- ;;view-deactivate-event-handler
- ;;
- ;;this function is called whenever the scrollbar needs to be deactivated
- ;;
-
- (defmethod view-deactivate-event-handler ((item scroll-bar-dialog-item))
- (let ((handle (dialog-item-handle item))
- (container (view-container item)))
- (when handle
- (with-focused-view container
- (unless (window-active-p (view-window item))
- (multiple-value-bind (tl br) (scroll-bar-and-splitter-corners item)
- (rlet ((rect :rect
- :topLeft (add-points tl #@(1 1))
- :botRight (subtract-points br #@(1 1))))
- (with-clip-rect rect
- ; #_HideControl invals outside of the clip rect. Naughty, naughty.
- (let* ((wptr (href handle :controlRecord.ContrlOwner))
- (update-rgn (pref wptr :windowRecord.updateRgn))
- (temp-rgn *temp-rgn*))
- (declare (dynamic-extent wptr update-rgn)
- (type macptr wptr update-rgn))
- (#_CopyRgn update-rgn temp-rgn)
- (#_HideControl handle)
- (#_CopyRgn temp-rgn update-rgn))
- (#_EraseRect rect)
- (validate-corners container tl br))))))
- (#_hilitecontrol handle 255))))
-
- ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
- ;;view-activate-event-handler
- ;;
- ;;this function is called whenever the scrollbar needs to be activated
- ;;
-
- (defmethod view-activate-event-handler ((item scroll-bar-dialog-item))
- (when (let ((w (view-window item)))
- (and w (window-active-p w)))
- (let ((handle (dialog-item-handle item))
- (container (view-container item)))
- (with-focused-view container
- (when (dialog-item-enabled-p item)
- (#_hilitecontrol handle 0))
- (unless (neq 0 (rref handle :controlRecord.ContrlVis))
- ; #_ShowControl is similarly naughty
- (let* ((wptr (href handle :controlRecord.ContrlOwner))
- (update-rgn (pref wptr :windowRecord.updateRgn))
- (temp-rgn *temp-rgn*))
- (declare (dynamic-extent wptr update-rgn)
- (type macptr wptr update-rgn))
- (#_CopyRgn update-rgn temp-rgn)
- (#_ShowControl handle)
- (#_CopyRgn temp-rgn update-rgn))
- (let ((splitter (pane-splitter item)))
- (when splitter (view-draw-contents splitter)))
- (multiple-value-bind (tl br) (scroll-bar-and-splitter-corners item)
- (validate-corners container tl br)))))))
-
-
- ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
- ;;dialog-item-enable
- ;;
- ;; Need to patch the system-supplied method for control-dialog-item
- ;; scroll bars are not visibly enabled unless the window they're on
- ;; is the top window.
-
- (defmethod dialog-item-enable ((item scroll-bar-dialog-item))
- (unless (dialog-item-enabled-p item)
- (setf (dialog-item-enabled-p item) t)
- (view-activate-event-handler item)))
-
-
- ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
- ;;dialog-item-disable
- ;;
- ;; Patch the control-dialog-item method to delay
- ;; the actual disable during scrolling.
- ;; This gets around a bug in the Mac ROM where the scroll
- ;; a control is enabled just before #_TrackControl returns.
-
- ; This is bound to the scroll bar that is currently being tracked.
- (defvar *scroll-bar-item* nil)
-
- (defmethod dialog-item-disable ((item scroll-bar-dialog-item))
- (if (eq item *scroll-bar-item*)
- (setf (dialog-item-enabled-p item) nil)
- (call-next-method)))
-
- ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
- ;;scroll-bar-proc
- ;;
- ;;this is the hook function which is passed to _TrackControl. The toolbox
- ;; will call this function periodically as the control is clicked.
- ;;
- ;; It calls track-scroll-bar every time the ROM calls it.
- ;; The default version of track-scroll-bat updates the
- ;; scroll bar position according to the scroll-bar-scroll-size or
- ;; scroll-bar-page-size and calls dialog-item-action.
- ;; User's may shadow the default method if they need custom behavior.
-
- (defpascal scroll-bar-proc (:ptr sb-handle :word part)
- "This procedure adjusts the control value, and calls dialog-item-action."
- (let ((item *scroll-bar-item*))
- (track-scroll-bar
- item
- (if (eq part #.$InThumb)
- (outside-scroll-bar-setting item sb-handle)
- (scroll-bar-setting item))
- (case part
- (#.$InUpButton :in-up-button)
- (#.$InDownButton :in-down-button)
- (#.$InPageUp :in-page-up)
- (#.$InPageDown :in-page-down)
- (#.$InThumb :in-thumb)
- (t nil)))))
-
- (eval-when (:compile-toplevel :execute)
- (require "LISPEQU")) ; for $ptask_draw-flag
-
- ;; Unfortunately, the ROM is brain-damaged, so we have to do this ourselves.
- (defun track-scroll-bar-thumb (item)
- (let* ((old-setting (scroll-bar-setting item))
- (min (scroll-bar-min item))
- (max (scroll-bar-max item))
- (horizontal? (eq (scroll-bar-direction item) :horizontal))
- (position (view-position item))
- (last-mouse (rref *current-event* :eventRecord.where))
- (size (view-size item))
- (real-time-tracking (scroll-bar-track-thumb-p item))
- ; disable periodic tasks that draw
- (*periodic-task-mask* (logior (the fixnum *periodic-task-mask*)
- $ptask_draw-flag))
- width length old-mouse left right mouse setting)
- (setq last-mouse
- ; global-to-local
- (add-points (view-origin item)
- (subtract-points last-mouse (view-position (view-window item)))))
- (if horizontal?
- (setq width (point-v size)
- length (- (point-h size) width width width)
- left (+ (round (* width 3) 2) (point-h position))
- old-mouse (point-h last-mouse))
- (setq width (point-h size)
- length (- (point-v size) width width width)
- left (+ (round (* width 3) 2) (point-v position))
- old-mouse (point-v last-mouse)))
- (setq right (+ left length))
- (loop
- (unless (mouse-down-p)
- (unless (or real-time-tracking (not setting))
- (track-scroll-bar item setting :in-thumb))
- (return))
- (setq mouse (view-mouse-position item))
- (unless (eql mouse last-mouse)
- (setq last-mouse mouse)
- (setq mouse (if horizontal? (point-h mouse) (point-v mouse)))
- (setq setting (min max
- (max min
- (+ old-setting
- (round (* (- mouse old-mouse) (- max min))
- (- right left))))))
- (if real-time-tracking
- (track-scroll-bar item setting :in-thumb)
- (set-scroll-bar-setting item setting))))))
-
- ; Returns the new value for the scroll bar
- (defmethod track-scroll-bar ((item scroll-bar-dialog-item) value part)
- (set-scroll-bar-setting
- item
- (case part
- (:in-up-button (- value (scroll-bar-scroll-size item)))
- (:in-down-button (+ value (scroll-bar-scroll-size item)))
- (:in-page-up (- value (scroll-bar-page-size item)))
- (:in-page-down (+ value (scroll-bar-page-size item)))
- (t value)))
- (dialog-item-action item))
-
-
- ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
- ;;view-click-event-handler
- ;;
- ;;this is the function which is called when the user clicks in the scroll-bar
- ;;
- ;;It checks the scroll-bar part, and calls _TrackControl
- ;; If appropriate, it passes a hook function to _TrackControl
- ;;
- ;;During tracking, dialog-item-action is repeatedly called.
- ;;
-
- (defmethod view-click-event-handler ((item scroll-bar-dialog-item) where)
- (let* ((sb-handle (dialog-item-handle item))
- (part (#_TestControl sb-handle where)))
- (cond ((eq part #.$InThumb)
- (if (scroll-bar-track-thumb-p item)
- (track-scroll-bar-thumb item)
- (progn
- (let ((*scroll-bar-item* item))
- (#_TrackControl sb-handle where (%null-ptr)))
- (track-scroll-bar
- item (outside-scroll-bar-setting item sb-handle) :in-thumb))))
- ((memq part '(#.$InUpButton #.$InDownButton
- #.$InPageUp #.$InPageDown))
- (let ((was-enabled (dialog-item-enabled-p item)))
- (let ((*scroll-bar-item* item))
- (#_TrackControl sb-handle where scroll-bar-proc))
- ; The ROM enables on its way out
- (when (and was-enabled (not (dialog-item-enabled-p item)))
- (#_HiliteControl sb-handle 255)))))))
-
-
-
- ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
- ;;dialog-item-action
- ;;
- ;;The default dialog-item-action for a scroll bar calls
- ;;scroll-bar-changed on the scrollee
- ;;
- (defmethod dialog-item-action ((item scroll-bar-dialog-item))
- (let ((f (dialog-item-action-function item)))
- (if f
- (funcall f item)
- (let ((scrollee (scroll-bar-scrollee item)))
- (when scrollee
- (scroll-bar-changed scrollee item))))))
-
- (defmethod scroll-bar-changed (view scroll-bar)
- (declare (ignore view scroll-bar)))
-
- ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
- ;;(setf scroll-bar-setting)
- ;;
- ;;a nice safe Lisp-level function for changing the value of the scroll-bar
- ;;The accessor is defined by the DEFCLASS
- ;;
-
- (defmethod (setf scroll-bar-setting) (new-value (item scroll-bar-dialog-item))
- (set-scroll-bar-setting item new-value))
-
- (defmethod set-scroll-bar-setting ((item scroll-bar-dialog-item) new-value)
- (setq new-value (require-type new-value 'fixnum))
- (%set-scroll-bar-setting item new-value t))
-
- (defun %set-scroll-bar-setting (item new-value only-if-new-value)
- (setq new-value (max (scroll-bar-min item) (min (scroll-bar-max item) new-value)))
- (unless (and only-if-new-value (eql new-value (scroll-bar-setting item)))
- (let ((handle (dialog-item-handle item)))
- (when handle
- (with-focused-view (view-container item)
- (#_SetCtlValue
- handle
- (mac-scroll-bar-setting
- new-value
- (scroll-bar-min item)
- (scroll-bar-max item))))))
- (setf (slot-value item 'setting) new-value))
- new-value)
-
- ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
- ;;scroll-bar-min is a :reader for the class
- ;;here's the setter
- ;;
- (defmethod (setf scroll-bar-min) (new-value (item scroll-bar-dialog-item))
- (set-scroll-bar-min item new-value))
-
- (defmethod set-scroll-bar-min ((item scroll-bar-dialog-item) new-value)
- (setq new-value (require-type new-value 'fixnum))
- (unless (eql new-value (scroll-bar-min item))
- (setf (slot-value item 'min) new-value)
- (update-scroll-bar-max-min-setting item))
- new-value)
-
-
- ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
- ;;scroll-bar-max is a :reader for the class
- ;;here's the setter
- ;;
- (defmethod (setf scroll-bar-max) (new-value (item scroll-bar-dialog-item))
- (set-scroll-bar-max item new-value))
-
- (defmethod set-scroll-bar-max ((item scroll-bar-dialog-item) new-value)
- (setq new-value (require-type new-value 'fixnum))
- (unless (eql new-value (scroll-bar-max item))
- (setf (slot-value item 'max) new-value)
- (update-scroll-bar-max-min-setting item))
- new-value)
-
- (defun update-scroll-bar-max-min-setting (item)
- (let ((handle (dialog-item-handle item)))
- (when handle
- (with-focused-view (view-container item)
- (let ((max (scroll-bar-max item))
- (min (scroll-bar-min item))
- (setting (scroll-bar-setting item)))
- (multiple-value-bind (mac-min mac-max) (mac-scroll-bar-min-max min max)
- (let ((mac-setting (mac-scroll-bar-setting setting min max mac-min mac-max)))
- (cond ((not (eql mac-min (href handle :controlrecord.contrlmin)))
- (setf (href handle :controlrecord.contrlmax) mac-max
- (href handle :controlrecord.contrlvalue) mac-setting)
- (#_SetCtlMin handle mac-min))
- ((not (eql mac-max (href handle :controlrecord.contrlmax)))
- (setf (href handle :controlrecord.contrlmin) mac-min
- (href handle :controlrecord.contrlvalue) mac-setting)
- (#_SetCtlMax handle mac-max))
- (t
- (setf (href handle :controlrecord.contrlmin) mac-min
- (href handle :controlrecord.contrlmax) mac-max)
- (#_SetCtlValue handle mac-setting))))))))))
-
-
- ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
- ;;scroll-bar-length
- ;;
- ;;this is a variation of view-size
- ;;
- ;;It only used one dimension, since scroll-bars almost always have a width
- ;; of 16 pixels.
- ;;
-
- (defmethod scroll-bar-length ((item scroll-bar-dialog-item))
- (let* ((size (view-size item))
- (splitter (pane-splitter item))
- (splitter-size (and splitter (view-size splitter))))
- (if (eq (scroll-bar-direction item) :horizontal)
- (+ (point-h size) (if splitter (point-h splitter-size) 0))
- (+ (point-v size) (if splitter (point-v splitter-size) 0)))))
-
-
- ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
- ;;set-scroll-bar-length
- ;;
- ;;sets the length of the scroll-bar
- ;;
- ;;Note that because of the way this is implemented, you MUST
- ;;change the length of a scroll bar with a splitter with
- ;;set-scroll-bar-length, not by calling set-view-size directly
- ;;
-
- (defun (setf scroll-bar-length) (new-length scroll-bar-dialog-item)
- (set-scroll-bar-length scroll-bar-dialog-item new-length))
-
- (defmethod set-scroll-bar-length ((item scroll-bar-dialog-item) new-length)
- (let ((splitter (pane-splitter item))
- (direction (scroll-bar-direction item))
- (inner-length new-length))
- (when splitter
- (let ((size (view-size splitter)))
- (decf inner-length
- (min inner-length
- (if (eq direction :horizontal) (point-h size) (point-v size))))))
- (set-view-size item (if (eq direction :horizontal)
- (make-point inner-length (scroll-bar-width item))
- (make-point (scroll-bar-width item) inner-length)))
- (when splitter
- (set-view-position item (view-position item))))
- new-length)
-
- ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
- ;;scroll-bar-width
- ;;
- ;; Sometimes you want a different width
- ;;
- (defmethod scroll-bar-width ((item scroll-bar-dialog-item))
- (let ((size (view-size item)))
- (if (eq (scroll-bar-direction item) :horizontal)
- (point-v size)
- (point-h size))))
-
-
- ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
- ;;set-scroll-bar-width
- ;;
- ;;sets the width of the scroll-bar
- ;;
- ;;Note that because of the way this is implemented, you MUST
- ;;change the width of a scroll bar with a splitter with
- ;;set-scroll-bar-width, not by calling set-view-size directly
- ;;
-
- (defun (setf scroll-bar-width) (new-length scroll-bar-dialog-item)
- (set-scroll-bar-width scroll-bar-dialog-item new-length))
-
- (defmethod set-scroll-bar-width ((item scroll-bar-dialog-item) new-width)
- (let ((size (view-size item)))
- (set-view-size item (if (eq (scroll-bar-direction item) :horizontal)
- (make-point (point-h size) new-width)
- (make-point new-width (point-v size)))))
- (let ((splitter (pane-splitter item)))
- (if splitter
- (let ((size (view-size splitter)))
- (set-view-size splitter (if (eq (scroll-bar-direction splitter) :horizontal)
- (make-point (point-h size) new-width)
- (make-point new-width (point-v size)))))))
- new-width)
-
- ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
- ;;(setf scroll-bar-scrollee)
- ;;
- ;;Change the scrollee of a scroll-bar
- ;;
- (defun (setf scroll-bar-scrollee) (new-scrollee scroll-bar-dialog-item)
- (set-scroll-bar-scrollee scroll-bar-dialog-item new-scrollee))
-
- (defmethod set-scroll-bar-scrollee ((item scroll-bar-dialog-item) new-scrollee)
- (let ((old-scrollee (scroll-bar-scrollee item)))
- (when old-scrollee
- (delete-view-scroll-bar old-scrollee item)))
- (add-view-scroll-bar new-scrollee item)
- (let ((splitter (pane-splitter item)))
- (if splitter (set-scroll-bar-scrollee splitter new-scrollee)))
- (setf (slot-value item 'scrollee) new-scrollee))
-
- ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
- ;; pass set-view-container and set-view-position
- ;; to the pane-splitter
- ;;
- (defmethod set-view-container ((item scroll-bar-dialog-item) new-container)
- (let ((splitter (pane-splitter item)))
- (when splitter
- (set-view-container splitter new-container))
- (call-next-method)))
-
- (defmethod set-view-position ((item scroll-bar-dialog-item) h &optional v)
- (let ((pos (make-point h v))
- (splitter (pane-splitter item))
- (splitter-position (pane-splitter-position item)))
- (setq h (point-h pos) v (point-v pos))
- (when splitter
- (let ((size (view-size item))
- (s-size (view-size splitter)))
- (if (eq (scroll-bar-direction item) :horizontal)
- (if (eq splitter-position :left)
- (progn (set-view-position splitter pos)
- (incf h (point-h s-size)))
- (set-view-position splitter (+ h (point-h size)) v))
- (if (eq splitter-position :top)
- (progn (set-view-position splitter pos)
- (incf v (point-v s-size)))
- (set-view-position splitter h (+ v (point-v size))))))))
- (call-next-method item h v))
-
- (defmethod corrected-view-position ((item scroll-bar-dialog-item))
- (let ((splitter (pane-splitter item)))
- (if (and splitter (memq (pane-splitter-position item) '(:top :left)))
- (view-position splitter)
- (view-position item))))
-
- ; Change the relative position of a scroll bar's pane splitter.
- ; :top <-> :bottom
- ; :left <-> :right
- (defmethod set-pane-splitter-position ((item scroll-bar-dialog-item) pos)
- (let ((position (corrected-view-position item)))
- (setf (slot-value item 'pane-splitter-position) pos)
- (set-view-position item position))
- pos)
-
- ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
- ;;
- ;; set-view-size needs to invalidate the entire scroll bar
- ;; if it is inactive.
- ;;
- (defmethod set-view-size ((view scroll-bar-dialog-item) h &optional v)
- (declare (ignore h v))
- (without-interrupts
- (prog1
- (call-next-method)
- (let ((w (view-window view)))
- (when w
- (unless (window-active-p w)
- (multiple-value-bind (tl br) (scroll-bar-and-splitter-corners view)
- (invalidate-corners
- (view-container view) (add-points tl #@(1 1)) br t))))))))
-
- ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
- ;;
- ;; Methods for pane-splitter
- ;;
- (defmethod initialize-instance ((item pane-splitter) &rest initargs
- &key (width 16) (length 5) (direction :vertical))
- (declare (dynamic-extent initargs))
- (let ((size (if (eq direction :vertical)
- (make-point width length)
- (make-point length width))))
- (apply #'call-next-method
- item
- :view-size size
- :direction direction
- initargs)))
-
- (defmethod view-draw-contents ((item pane-splitter))
- (when (window-active-p (view-window item))
- (let* ((tl (view-position item))
- (br (add-points tl (view-size item))))
- (rlet ((r :rect :topleft tl :botright br))
- (#_FillRect r *black-pattern*)))))
-
- (defmethod view-click-event-handler ((item pane-splitter) where)
- (declare (ignore where))
- (let* ((scrollee (or (scroll-bar-scrollee item) (view-window item)))
- (window (view-window item))
- (scroll-bar (scroll-bar item)))
- (when window
- (multiple-value-bind (s-tl s-br)
- (pane-splitter-corners scrollee scroll-bar)
- (let* ((wait-ticks (max 1 (floor internal-time-units-per-second 30)))
- (direction (scroll-bar-direction item))
- (win-min -20)
- (mouse-pos (view-mouse-position window))
- min max min-pos max-pos drawn time pos-accessor line-direction delta pos
- win-accessor win-max)
- (if (eq direction :vertical)
- (setq min (1+ (point-h s-tl))
- max (- (point-h s-br) 2)
- min-pos (1+ (point-v s-tl))
- max-pos (- (point-v s-br) 2)
- pos-accessor #'point-v
- win-accessor #'point-h
- win-max (+ 20 (point-h (view-size window)))
- line-direction :horizontal)
- (setq min (1+ (point-v s-tl))
- max (- (point-v s-br) 2)
- min-pos (1+ (point-h s-tl))
- max-pos (- (point-h s-br) 2)
- pos-accessor #'point-h
- win-accessor #'point-v
- win-max (point-v (view-size window))
- line-direction :vertical))
- ; Compute the initial position for the outline.
- ; All this rigamarole is to convert from the window's coordinate system
- ; to the scrollee's and back again.
- (setq pos
- (let ((pos (pane-splitter-outline-position
- scrollee scroll-bar
- (convert-coordinates mouse-pos window scrollee))))
- (funcall pos-accessor
- (convert-coordinates
- (if (eq direction :vertical)
- (make-point 0 pos)
- (make-point pos 0))
- scrollee
- window)))
- delta (- pos (funcall pos-accessor mouse-pos)))
- ; Now loop until mouse up.
- (flet ((draw-line (pos)
- (draw-pane-splitter-outline
- scrollee scroll-bar pos min max line-direction)
- (setq drawn (not drawn)
- time (get-internal-run-time))))
- (declare (dynamic-extent #'draw-line))
- (with-focused-view window
- (with-pen-saved
- (#_PenPat *gray-pattern*)
- (#_PenMode (position :patxor *pen-modes*))
- (draw-line pos)
- (unwind-protect
- (loop
- (unless (mouse-down-p) (return))
- (let* ((new-mouse (view-mouse-position window))
- (new-pos (+ delta (funcall pos-accessor new-mouse)))
- (in-window (<= win-min
- (funcall win-accessor new-mouse)
- win-max)))
- (unless (or (eql mouse-pos new-mouse)
- (<= (get-internal-run-time) (+ time wait-ticks)))
- (when (and drawn (or (not (eql new-pos pos)) (not in-window)))
- (draw-line pos))
- (setq pos new-pos mouse-pos new-mouse)
- (when (and (not drawn) (<= min-pos pos max-pos) in-window)
- (draw-line pos)))))
- (when drawn
- (draw-line pos)
- (setq drawn t))))))
- ; Convert back to scrollee's coordinate system
- (setq pos (funcall pos-accessor (convert-coordinates
- (if (eq direction :horizontal)
- (make-point pos 0)
- (make-point 0 pos))
- window
- scrollee)))
- ; And call the user method to actually do something.
- (split-pane scrollee scroll-bar pos direction drawn))))))
-
- ; This controls the position of the outline when the mouse is first clicked.
- ; mouse-position is the position of the mouse in the coordinate system of
- ; the scrollee.
- ; The default method draws the outline right where the mouse is.
- (defmethod pane-splitter-outline-position (scrollee scroll-bar mouse-position)
- (declare (ignore scrollee))
- (if (eq (scroll-bar-direction scroll-bar) :vertical)
- (point-v mouse-position)
- (point-h mouse-position)))
-
- (defmethod draw-pane-splitter-outline (scrollee scroll-bar pos min max direction)
- (declare (ignore scrollee scroll-bar))
- (if (eq direction :horizontal)
- (progn (#_MoveTo min pos)
- (#_LineTo max pos))
- (progn (#_MoveTo pos min)
- (#_LineTo pos max))))
-
- ; Some users may want to specialize on this
- (defmethod pane-splitter-corners ((scrollee simple-view) scroll-bar)
- (declare (ignore scroll-bar))
- (let* ((window (view-window scrollee))
- (container (view-container scrollee)))
- (multiple-value-bind (tl br) (view-corners scrollee)
- (when (and container (neq container window))
- (setq tl (convert-coordinates tl container window)
- br (convert-coordinates br container window)))
- (values tl br))))
-
- ; This is the method that all users will specialize on if they
- ; want a pane-splitter to do anything but draw a line.
- (defmethod split-pane ((scrollee simple-view) scroll-bar pos direction inside-limits)
- (declare (ignore scroll-bar pos direction inside-limits)))
-
-
- (provide 'scroll-bar-dialog-items)
-
- #|
- ;; a simple example.
- ;; Shows what the :track-thumb-p initarg does.
- ;; Also shows two different ways to make the scroll bar work:
- ;; 1) scroll bar's dialog-item-action does the work
- ;; 2) scrollee's scroll-bar-changed method does the work.
-
- (defclass scroll-bar-display (static-text-dialog-item) ())
-
- (defmethod scroll-bar-changed ((scrollee scroll-bar-display)
- scroll-bar)
- (set-dialog-item-text
- scrollee (format nil "~3d" (scroll-bar-setting scroll-bar)))
- (view-focus-and-draw-contents scrollee))
-
- (defun scroll-bar-example ()
- (let* ((dialog (make-instance 'dialog
- :view-size #@(250 145)
- :window-title "Scroll Bar Example"))
- (display (make-instance 'scroll-bar-display
- :view-position #@(25 80)
- :dialog-item-text "000"
- :view-container dialog)))
- ; This scroll bar gets its work done via scroll-bar-changed
- ; And will update immediately when you drag its thumb.
- (make-instance 'scroll-bar-dialog-item
- :view-position #@(25 120)
- :direction :horizontal
- :length 200
- :scrollee display
- :view-container dialog
- :track-thumb-p t)
-
- ; this scroll bar does it's work itself
- ; and will respond to a thumb drag only after you're done.
- (make-instance 'static-text-dialog-item
- :view-position #@(25 10)
- :dialog-item-text "000"
- :view-nick-name 'display-text
- :view-container dialog)
- (make-instance 'scroll-bar-dialog-item
- :view-position #@(25 50)
- :direction :horizontal
- :length 200
- :view-container dialog
- :dialog-item-action
- #'(lambda (item &aux (setting (format nil "~a"
- (scroll-bar-setting item))))
- (set-dialog-item-text
- (find-named-sibling item 'display-text)
- setting)
- (window-update-event-handler (view-window item))))))
-
- (scroll-bar-example)
-
-
- |#
-